using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Net;
using System.Text.RegularExpressions;
using System.Xml;

using Service = Kiiro.MSProjectPlugin.PluginHelpers.Service;
using System.Reflection;

namespace Kiiro.MSProjectPlugin
{
    /// <summary>
    ///   Add-in Express Add-in Module
    /// </summary>
    [GuidAttribute ( "B259FC99-B957-485A-9431-C9E01D6E5315" ), ProgId ( "Kiiro.MSProjectPlugin.AddinModule" )]
    public class AddinModule : AddinExpress.MSO.ADXAddinModule
    {
        #region Add-in Express automatic code

        // Required by Add-in Express - do not modify
        // the methods within this region 
        public override System.ComponentModel.IContainer GetContainer()
        {
            if (components == null)
                components = new System.ComponentModel.Container();
            return components;
        }

        [ComRegisterFunctionAttribute]
        public static void AddinRegister(Type t)
        {
            AddinExpress.MSO.ADXAddinModule.ADXRegister(t);
        }

        [ComUnregisterFunctionAttribute]
        public static void AddinUnregister(Type t)
        {
            AddinExpress.MSO.ADXAddinModule.ADXUnregister(t);
        }

        public override void UninstallControls()
        {
            base.UninstallControls();
        }

        #endregion

        #region Properties

        public MSProject._MSProject MSProjectApp
        {
            get
            {
                return (HostApplication as MSProject._MSProject);
            }
        }

        public List<Service> Services = new List<Service>();       

        public AddinModule ( )
        {
            InitializeComponent ( );
            // Please add any initialization code to the AddinInitialize event handler
        }

        private AddinExpress.MSO.ADXCommandBar adxMidori;
        private AddinExpress.MSO.ADXCommandBarButton adxSync;
        private AddinExpress.MSO.ADXProjectAppEvents adxProjectEvents;
        private System.Windows.Forms.ImageList ilImages;
        public PluginHelpers.PromptForm prompt = null;
        public bool HideTaskPane = false;
        
        // global regex expression
        Regex PATH_VALIDATOR { get { return new Regex ( "https?://.+/Documents" ); } }

        public class WindowWrapper : System.Windows.Forms.IWin32Window
        {
            public WindowWrapper(IntPtr handle)
            {
                _hwnd = handle;
            }

            public IntPtr Handle
            {
                get { return _hwnd; }
            }

            private IntPtr _hwnd;
        }

        #endregion

        #region Component Designer generated code
        /// <summary>
        /// Required by designer
        /// </summary>
        private System.ComponentModel.IContainer components;

        /// <summary>
        /// Required by designer support - do not modify
        /// the following method
        /// </summary>
        private void InitializeComponent ( )
        {
            this.components = new System.ComponentModel.Container ( );
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager ( typeof ( AddinModule ) );
            this.adxMidori = new AddinExpress.MSO.ADXCommandBar ( this.components );
            this.adxSync = new AddinExpress.MSO.ADXCommandBarButton ( this.components );
            this.ilImages = new System.Windows.Forms.ImageList ( this.components );
            this.adxProjectEvents = new AddinExpress.MSO.ADXProjectAppEvents ( this.components );
            // 
            // adxMidori
            // 
            this.adxMidori.CommandBarName = "Kiiro";
            this.adxMidori.CommandBarTag = "e1f3ed77-41ab-4b2a-b861-588714225d0d";
            this.adxMidori.Controls.Add ( this.adxSync );
            this.adxMidori.Position = AddinExpress.MSO.ADXMsoBarPosition.adxMsoBarTop;
            this.adxMidori.Protection = AddinExpress.MSO.ADXMsoBarProtection.adxMsoBarNoChangeVisible;
            this.adxMidori.SupportedApps = AddinExpress.MSO.ADXOfficeHostApp.ohaProject;
            this.adxMidori.Temporary = true;
            this.adxMidori.UpdateCounter = 13;
            this.adxMidori.UseForRibbon = true;
            this.adxMidori.Visible = false;
            // 
            // adxSync
            // 
            this.adxSync.Caption = "Synchronize changes with Kiiro";
            this.adxSync.ControlTag = "a39d62f7-cc72-4b0d-abcc-ba5ae69d84e0";
            this.adxSync.Image = 0;
            this.adxSync.ImageList = this.ilImages;
            this.adxSync.ImageTransparentColor = System.Drawing.Color.Transparent;
            this.adxSync.Style = AddinExpress.MSO.ADXMsoButtonStyle.adxMsoButtonIcon;
            this.adxSync.Temporary = true;
            this.adxSync.UpdateCounter = 12;
            //this.adxSync.Click += new AddinExpress.MSO.ADXClick_EventHandler ( this.adxSync_Click );
            // 
            // ilImages
            // 
            this.ilImages.ImageStream = ( ( System.Windows.Forms.ImageListStreamer ) ( resources.GetObject ( "ilImages.ImageStream" ) ) );
            this.ilImages.TransparentColor = System.Drawing.Color.Transparent;
            this.ilImages.Images.SetKeyName ( 0, "kiiroico.gif" );
            // 
            // adxProjectEvents
            // 
            this.adxProjectEvents.WindowActivate += new AddinExpress.MSO.ADXHostActiveObject_EventHandler ( this.adxProjectEvents_WindowActivate );
            this.adxProjectEvents.ProjectBeforeSave += new AddinExpress.MSO.ADXHostBeforeSave_EventHandler(adxProjectEvents_ProjectBeforeSave);
            this.adxProjectEvents.ProjectBeforeClose += new AddinExpress.MSO.ADXHostBeforeAction_EventHandler(adxProjectEvents_ProjectBeforeClose);
            this.adxProjectEvents.ApplicationBeforeClose += new AddinExpress.MSO.ADXProjectBeforeClose_EventHandler(adxProjectEvents_ApplicationBeforeClose);
            // 
            // AddinModule
            // 
            this.AddinName = "Kiiro.MSProjectPlugin";
            this.SupportedApps = AddinExpress.MSO.ADXOfficeHostApp.ohaProject;
            this.AddinBeginShutdown += new AddinExpress.MSO.ADXEvents_EventHandler ( this.AddinModule_AddinBeginShutdown );         
        }     
     
        #endregion

        #region Methods
        
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern bool SetForegroundWindow(IntPtr hwnd);

        private Service InList(string path, string name)
        {
            foreach (Service service in Services)
            {
                if (service.Path == path)
                {
                    if (service.Name == name)                    
                        return service;                    
                    else
                    {
                        Service newName = new Service(name, path);
                        newName.Cookie = service.Cookie;
                        newName.Credentials = service.Credentials;
                        newName.UserId = service.UserId;
                        return newName;
                    }
                }
            }

            HideTaskPane = true;
            Service project = new Service(name, path);
            Services.Add(project);
            return project;
        }

        private void RemoveFromList(Service service)
        {
            bool remove = false;

            foreach (Service s in Services)
            {
                if (s.Path == service.Path)
                {
                    if (s.Name == service.Name)
                    {
                        service = s;
                        remove = true;
                    }
                }
            }

            if (remove)
                Services.Remove(service);
        }

        private void ShowDialog()
        {
            System.Threading.Thread modalThread = new System.Threading.Thread(ModalThread);
            modalThread.Start();
            while (!prompt.Visible)
                Application.DoEvents();
            Application.DoEvents();
        }

        private void ModalThread()
        {
            prompt.ShowDialog(new WindowWrapper(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle));            
        }          

        private void AddinModule_AddinBeginShutdown ( object sender, EventArgs e )
        {
            while ( Marshal.ReleaseComObject ( MSProjectApp ) > 0 )
                Marshal.ReleaseComObject ( MSProjectApp );
        }

        private void adxProjectEvents_WindowActivate ( object sender, object hostObj )
        {           
            
            Cursor.Current = Cursors.WaitCursor;
            MSProject.Project project = null;

            try
            {
                prompt = new PluginHelpers.PromptForm();
                prompt.Waiting();                
                               
                project = MSProjectApp.ActiveProject;
                string path = project.Path;
                string fullName = project.FullName;                

                if ( path != null && PATH_VALIDATOR.IsMatch ( path ) )
                {
                    Service service = InList(path, fullName);                    

                    if (!project.ReadOnly)
                    {
                        if (service.UserId <= 0)
                        {
                            ShowDialog();
                            PluginModel.IsUserValid(service, prompt);

                            if (service.UserId > 0)
                            {                                
                                bool firstSync = true;
                                bool isDirty = false;

                                PluginModel.IsDirty(service, out firstSync, out isDirty);

                                bool versionOk = false;
                                versionOk = PluginModel.VersionCheck(service, Assembly.GetExecutingAssembly().GetName().Version);

                                if (versionOk)
                                {
                                    if (firstSync) { }
                                    else
                                    {
                                        XmlDocument oldTasks = new XmlDocument();
                                        oldTasks.LoadXml("<Tasks></Tasks>");
                                        foreach (MSProject.Task task in project.Tasks)
                                        {
                                            if (task != null && task.OutlineChildren.Count == 0)                                            
                                                oldTasks = PluginHelpers.TaskToXml(oldTasks, task);                                            
                                        }
                                        service.OldTasks = oldTasks;

                                        PluginModel.DownloadMidoriToProject(project, service);
                                        PluginModel.SyncProjectToMidori(project, service);

                                        oldTasks = new XmlDocument();
                                        oldTasks.LoadXml("<Tasks></Tasks>");
                                        foreach (MSProject.Task task in project.Tasks)
                                        {
                                            if (task != null && task.OutlineChildren.Count == 0)                                            
                                                oldTasks = PluginHelpers.TaskToXml(oldTasks, task);                                            
                                        }
                                        service.OldTasks = oldTasks;
                                    }
                                }
                                else
                                {
                                    service.UserId = 0;
                                    throw new Exception("Minimum Kiiro MSProject Plug-in not met. Kiiro Site requires a higher Plug-in version to synchronize. Please download the latest version of the Kiiro MSProject Plug-in");
                                }
                            }
                            else
                            {
                                prompt.Fail();                              
                                RemoveFromList(service);
                            }
                        }
                    }

                    MSProjectApp.CommandBars.OnUpdate += new Office._CommandBarsEvents_OnUpdateEventHandler(CommandBars_OnUpdate);
                }
            }
            catch (Exception ex)
            {
                if (prompt == null || !prompt.Visible)
                {
                    prompt = new PluginHelpers.PromptForm();
                    ShowDialog();
                }

                prompt.Exception(ex);                
            }
            finally
            {
                Cursor.Current = Cursors.Default;               

                if (prompt != null)
                {
                    prompt.DialogResult = DialogResult.Cancel;
                    prompt.Hide();
                    prompt = null;                    
                }

                SetForegroundWindow(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);

                foreach ( MSProject.Project prj in MSProjectApp.Projects )
                    while ( Marshal.ReleaseComObject ( prj ) > 0 )
                        Marshal.ReleaseComObject ( prj );
            }
        }

        private void CommandBars_OnUpdate()
        {            
            if (HideTaskPane)
            {
                foreach (Office.CommandBar cBar in MSProjectApp.CommandBars)
                {
                    if (cBar.Name == "Task Pane")
                    {
                        foreach (Office.CommandBarControl bControl in cBar.Controls)
                        {
                            if (bControl.Caption == "Shared Workspace")
                            {
                                if (bControl.Visible)
                                {
                                    cBar.Visible = false;
                                    HideTaskPane = false;
                                }
                                break;
                            }
                        }
                        break;
                    }
                }                
            }          
        }    

        private void adxProjectEvents_ProjectBeforeSave(object sender, AddinExpress.MSO.ADXHostBeforeSaveEventArgs e)
        {
            if (!e.SaveAsUI)
            {                
                Cursor.Current = Cursors.WaitCursor;
                MSProject.Project project = null;

                try
                {
                    project = (MSProject.Project)e.HostObject;

                    if (project != null && !project.ReadOnly)
                    {
                        string path = project.Path;
                        string fullName = project.FullName;

                        if ( path != null && PATH_VALIDATOR.IsMatch ( path ) )
                        {
                            Service service = InList(path, fullName);

                            if (service.UserId > 0)
                            {
                                Cursor.Current = Cursors.WaitCursor;
                                prompt = new PluginHelpers.PromptForm();
                                prompt.Waiting();
                                ShowDialog();

                                PluginModel.SyncProjectToMidori(project, service);
                                PluginModel.DownloadMidoriToProject(project, service);

                                XmlDocument oldTasks = new XmlDocument();
                                oldTasks.LoadXml("<Tasks></Tasks>");
                                foreach (MSProject.Task task in project.Tasks)
                                {
                                    if (task != null && task.OutlineChildren.Count == 0)                                    
                                        oldTasks = PluginHelpers.TaskToXml(oldTasks, task);                                    
                                }
                                service.OldTasks = oldTasks;
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    e.Cancel = true;

                    if (prompt == null || !prompt.Visible)
                    {
                        prompt = new PluginHelpers.PromptForm();
                        ShowDialog();
                    }

                    prompt.Exception(ex);
                }
                finally
                {
                    Cursor.Current = Cursors.Default;

                    if (prompt != null)
                    {
                        prompt.DialogResult = DialogResult.Cancel;
                        prompt.Hide();
                        prompt = null;
                    }

                    SetForegroundWindow(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);

                    foreach (MSProject.Project prj in MSProjectApp.Projects)
                        while (Marshal.ReleaseComObject(prj) > 0)
                            Marshal.ReleaseComObject(prj);
                }
            }
        }

        private void adxProjectEvents_ProjectBeforeClose(object sender, AddinExpress.MSO.ADXHostBeforeActionEventArgs e)
        {
            Cursor.Current = Cursors.WaitCursor;
            MSProject.Project project = null;

            try
            {
                project = (MSProject.Project)e.HostObject;

                if (project != null)
                {
                    string path = project.Path;
                    string fullName = project.FullName;

                    if ( path != null && PATH_VALIDATOR.IsMatch ( path ) && !project.ReadOnly )
                    {
                        Service service = InList(path, fullName);

                        if (service.UserId > 0 && !project.Saved && MSProjectApp.ActiveProject == project)                        
                            MSProjectApp.FileSave();                        

                        RemoveFromList(service);
                    }                    
                }
            }
            catch (Exception ex)
            {
                e.Cancel = true;

                if (prompt == null || !prompt.Visible)
                {
                    prompt = new PluginHelpers.PromptForm();
                    ShowDialog();
                }

                prompt.Exception(ex);                
            }
            finally
            {
                Cursor.Current = Cursors.Default;

                if (prompt != null)
                {
                    prompt.DialogResult = DialogResult.Cancel;
                    prompt.Hide();
                    prompt = null;
                }

                SetForegroundWindow(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);

                foreach (MSProject.Project prj in MSProjectApp.Projects)
                    while (Marshal.ReleaseComObject(prj) > 0)
                        Marshal.ReleaseComObject(prj);
            }
        }

        void adxProjectEvents_ApplicationBeforeClose(object sender, object info)
        {
            Cursor.Current = Cursors.WaitCursor;
            MSProject.Project project = null;

            try
            {
                foreach (MSProject.Project msp in MSProjectApp.Projects)
                {
                    project = msp;

                    if (project != null)
                    {
                        string path = project.Path;
                        string fullName = project.FullName;

                        if ( path != null && PATH_VALIDATOR.IsMatch ( path ) && !project.ReadOnly )
                        {
                            Service service = InList(path, fullName);

                            if (service.UserId > 0 && !project.Saved && MSProjectApp.ActiveProject == project)
                            {
                                MSProjectApp.FileSave();
                                break;
                            }

                            RemoveFromList(service);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                if (prompt == null || !prompt.Visible)
                {
                    prompt = new PluginHelpers.PromptForm();
                    ShowDialog();
                }

                prompt.Exception(ex);
            }
            finally
            {
                Cursor.Current = Cursors.Default;

                if (prompt != null)
                {
                    prompt.DialogResult = DialogResult.Cancel;
                    prompt.Hide();
                    prompt = null;
                }

                foreach (MSProject.Project prj in MSProjectApp.Projects)
                    while (Marshal.ReleaseComObject(prj) > 0)
                        Marshal.ReleaseComObject(prj);
            }
        }        

        #endregion
    }
}

/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.MSProjectPlugin/AddinModule.cs $
 * 
 * 17    10/27/09 5:35p Adamw
 * accomodations for moving plan file to document library:
 * -added IsProjectPlan to Documents list
 * -changed regex in plugin to allow for new path
 * -changed the method to getProject to use GetByRelativeUrl
 * -changed web service urls to allow for new path
 * 
 * 16    10/02/09 10:46a Stefanf
 * 
 * 15    8/31/09 3:36p Stefanf
 * 
 * 14    17/08/09 10:45a Camerons
 * Added check-in comments section
 * 
 ************************************************************************/